<?php
declare (strict_types = 1);
namespace app\common\model\user;

use think\db\exception\ModelNotFoundException;
use think\Exception;
use app\common\utils\facade\AideUtil;
use think\facade\Log;
use think\facade\Route;

class SignForm
{
    //邮件发送限数设置
    const EMAIL_LIMIT_KEY = 'register_email_limit'; //邮箱发送限数 KEY
    const EMAIL_LIMIT_NUM = 3; //没指定时间间隔内发送邮件次数
    const EMAIL_LIMIT_INTERVAL = 5*60; //5分钟内只能发送3次邮件

    const EMAIL_CAPTCHA_KEY = 'register_email_captcha';//邮箱验证码KEY
    const EMAIL_CAPTCHA_LEN = 6;//验证码长度
    const EMAIL_CAPTCHA_EXPIRE = 5*60;//邮箱验证码有效时间


    /**
     * 发送密码重置连接
     * @param string $username
     * @param string $mail
     * @return mixed
     * @throws Exception
     * @throws ModelNotFoundException
     */
    public static function sendResetPasswordToken(string $username, string $email){
        //邮件限速 5分钟内只能发送3条
        if( !AideUtil::setLimit(static::EMAIL_LIMIT_KEY, static::EMAIL_LIMIT_NUM, static::EMAIL_LIMIT_INTERVAL) ){
            throw new Exception('操作次数太多，休息一下吧。');
        }

        //查询用户
        $user = User::findIdentityByUsernameAndEmail($username,$email);
        if (!$user) throw new ModelNotFoundException('填写账号或邮箱错误.');

        //刷新reset password token
        if (!$user->generateResetPasswordToken()){
            throw new Exception('生成重置连接失败.');
        }

        //发送邮件
        $from = config('service.mail.username');
        $appName = config('app.app_name');
        $content = static::getResetPasswordContent($user);

        //发送验证码
        $mail = app()->mail;

        $mail->setMail(['address'=>$from, 'name'=>$appName], (array)$user->email);
        return $mail->sendMail('密码重置.', $content);
    }
    /**
     * 发送邮件验证码
     * @param $toEmail
     * @return bool
     * @throws
     */
    public static function sendMail($toEmail){
        //邮件限速 5分钟内只能发送3条
        if( !AideUtil::setLimit(static::EMAIL_LIMIT_KEY, static::EMAIL_LIMIT_NUM, static::EMAIL_LIMIT_INTERVAL) ){
            throw new Exception('操作次数太多，休息一下吧。');
        }

        //生成邮箱验证码
        $from = config('service.mail.username');
        $appName = config('app.app_name');
        $captcha = static::generateCaptcha($toEmail);
        $expire = static::EMAIL_CAPTCHA_EXPIRE / 60;
        $content = static::getEmailContent($appName,$captcha,$expire);
        //发送验证码
        $mail = app()->mail;
        $mail->setMail(['address'=>$from, 'name'=>$appName], (array) $toEmail);
        return $mail->sendMail('注册验证码.', $content);
    }

    /**
     * #创建邮件验证码内容
     * @param string $appName
     * @param string $captcha
     * @param int $expire
     * @return string
     */
    private static function getEmailContent(string $appName, string $captcha, int $expire){
        return <<<HTML
            您在 {$appName} 注册的验证码为 {$captcha}，请在{$expire}分钟之内使用，过期无效。
HTML;

    }

    /**
     * 生成重置密码邮件内容
     * @param User $user
     * @return string
     */
    private static function getResetPasswordContent(User $user){
        $resetLink = Route::buildUrl('showResetPassword',['token'=> $user->getResetPasswordTokenCrypt()])->domain(true);
        $expire = User::RESET_PASSWORD_TOKEN_EXPIRE / 60;
        return <<<HTML
        你好 {$user->username},点击以下链接 可完成密码重置，该链接 {$expire} 分钟之内有效，请及时使用。
        {$resetLink}
HTML;

    }

    /**
     * 生成验证码
     */
    private static function generateCaptcha(string $email){
        $len = static::EMAIL_CAPTCHA_LEN;
        $key = static::EMAIL_CAPTCHA_KEY;
        if($len <=0 || $len > 18) $len=6;
        $temStr = substr(uniqid(), -$len);

        //保存至session中
        $data = [
            'email' => $email,
            'captcha' => $temStr,
            'lifetime' => static::EMAIL_CAPTCHA_EXPIRE,
            'start_at' => time()
        ];
        app()->session->set($key, $data);
        return $temStr;
    }

    /**
     * 登录操作
     * @param string $account
     * @param string $password
     * @param bool $remember
     * @return bool
     * @throws Exception
     */
    public static function signin(string $account, string $password, bool $remember){
        try{
            $user = User::where([
                'username' => $account
            ])->whereOr([
                'email' => $account
            ])->find();
            if(!$user) throw new Exception('账号错误.');

            if (!$user->validatePassword($password)){
                throw new Exception('密码错误.');
            }
        }catch (\Exception $e){
            Log::warning('账户{account},密码{password}登录失败.',[
                'account' => $account,
                'password' => $password
            ]);
            throw new Exception('账号或密码错误.');
        }

        //如果要免登陆 更新 auth_key
        if( $remember )
            $user->save(['auth_key' => User::generateAuthKey()]);

        return app()->user->login($user, $remember ? 3600*24*7 : 0);

    }

}